{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "## 项目 : 预测波士顿房价\n",
    "\n",
    "\n",
    "欢迎来到 DSVC 《机器学习》研讨班第二周的项目！在此文件中，有些示例代码已经提供给你，但你还需要实现更多的功能来让项目成功运行。除非有明确要求，你无须修改任何已给出的代码。以**编程练习**开始的标题表示接下来的内容中有需要你必须实现的功能。每一部分都会有详细的指导，需要实现的部分也会在注释中以**TODO**标出。请仔细阅读所有的提示！\n",
    "\n",
    "除了实现代码外，你还**必须**回答一些与项目和实现有关的问题。每一个需要你回答的问题都会以**'问题 X'**为标题。请仔细阅读每个问题，并且在问题后的**'回答'**文字框中写出完整的答案。你的项目将会根据你对问题的回答和撰写代码所实现的功能来进行评分。\n",
    "\n",
    ">**提示：**Code 和 Markdown 区域可通过 **Shift + Enter** 快捷键运行。此外，Markdown可以通过双击进入编辑模式。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 第一步. 导入数据\n",
    "在这个项目中，你将利用马萨诸塞州波士顿郊区的房屋信息数据训练和测试一个模型，并对模型的性能和预测能力进行测试。通过该数据训练后的好的模型可以被用来对房屋做特定预测---尤其是对房屋的价值。对于房地产经纪等人的日常工作来说，这样的预测模型被证明非常有价值。\n",
    "\n",
    "此项目的数据集来自[UCI机器学习知识库(数据集已下线)](https://archive.ics.uci.edu/ml/datasets.html)。波士顿房屋这些数据于1978年开始统计，共506个数据点，涵盖了麻省波士顿不同郊区房屋14种特征的信息。本项目对原始数据集做了以下处理：\n",
    "- 有16个`'MEDV'` 值为50.0的数据点被移除。 这很可能是由于这些数据点包含**遗失**或**看不到的值**。\n",
    "- 有1个数据点的 `'RM'` 值为8.78. 这是一个异常值，已经被移除。\n",
    "- 对于本项目，房屋的`'RM'`， `'LSTAT'`，`'PTRATIO'`以及`'MEDV'`特征是必要的，其余不相关特征已经被移除。\n",
    "- `'MEDV'`特征的值已经过必要的数学转换，可以反映35年来市场的通货膨胀效应。\n",
    "\n",
    "运行下面区域的代码以载入波士顿房屋数据集，以及一些此项目所需的Python库。如果成功返回数据集的大小，表示数据集已载入成功。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 载入此项目所需要的库\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# 检查你的Python版本\n",
    "from sys import version_info\n",
    "if version_info.major != 2 and version_info.minor != 7:\n",
    "    raise Exception('请使用Python 2.7来完成此项目')\n",
    "    \n",
    "# 让可视化的结果在notebook中显示\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 载入波士顿房屋的数据集\n",
    "data = pd.read_csv('housing.csv')\n",
    "prices = data['MEDV']\n",
    "features = data.drop('MEDV', axis = 1)\n",
    "    \n",
    "# 完成\n",
    "print \"Boston housing dataset has {} data points with {} variables each.\".format(*data.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__下面三张图的横坐标分别是：住宅平均房间数量、区域中被认为是低收入阶层的比率和镇上学生与教师数量比例，纵坐标是房屋的中值价格__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(20, 10))\n",
    "plt.subplot(2, 2, 1)\n",
    "plt.title('RM')\n",
    "plt.scatter(features.get_values()[:, 0], prices.get_values())\n",
    "plt.subplot(2, 2, 2)\n",
    "plt.title('LSTAT')\n",
    "plt.scatter(features.get_values()[:, 1], prices.get_values())\n",
    "plt.subplot(2, 2, 3)\n",
    "plt.title('PTRATIO')\n",
    "plt.scatter(features.get_values()[:, 2], prices.get_values())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 第二步. 分析数据\n",
    "在项目的第一个部分，你会对波士顿房地产数据进行初步的观察并给出你的分析。通过对数据的探索来熟悉数据可以让你更好地理解和解释你的结果。\n",
    "\n",
    "由于这个项目的最终目标是建立一个预测房屋价值的模型，我们需要将数据集分为**特征(features)**和**目标变量(target variable)**。\n",
    "- **特征** `'RM'`， `'LSTAT'`，和 `'PTRATIO'`，给我们提供了每个数据点的数量相关的信息。\n",
    "- **目标变量**：` 'MEDV'`，是我们希望预测的变量。\n",
    "\n",
    "他们分别被存在`features`和`prices`两个变量名中。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 编程练习 1：基础统计运算\n",
    "你的第一个编程练习是计算有关波士顿房价的描述统计数据。我们已为你导入了` numpy `，你需要使用这个库来执行必要的计算。这些统计数据对于分析模型的预测结果非常重要的。\n",
    "在下面的代码中，你要做的是：\n",
    "- 计算`prices`中的`'MEDV'`的最小值、最大值、均值、中值和标准差；\n",
    "- 将运算结果储存在相应的变量中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#TODO 1\n",
    "\n",
    "#目标：计算价值的最小值\n",
    "minimum_price = None\n",
    "\n",
    "#目标：计算价值的最大值\n",
    "maximum_price = None\n",
    "\n",
    "#目标：计算价值的平均值\n",
    "mean_price = None\n",
    "\n",
    "#目标：计算价值的中值\n",
    "median_price = None\n",
    "\n",
    "#目标：计算价值的标准差\n",
    "std_price = None\n",
    "\n",
    "#目标：输出计算的结果\n",
    "print \"Statistics for Boston housing dataset:\\n\"\n",
    "print \"Minimum price: ${:,.2f}\".format(minimum_price)\n",
    "print \"Maximum price: ${:,.2f}\".format(maximum_price)\n",
    "print \"Mean price: ${:,.2f}\".format(mean_price)\n",
    "print \"Median price ${:,.2f}\".format(median_price)\n",
    "print \"Standard deviation of prices: ${:,.2f}\".format(std_price)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 问题 1 - 特征观察\n",
    "\n",
    "如前文所述，本项目中我们关注的是其中三个值:`'RM'`、`'LSTAT'` 和`'PTRATIO'`，对每一个数据点:\n",
    "- `'RM'` 是该地区中每个房屋的平均房间数量；\n",
    "- `'LSTAT'` 是指该地区有多少百分比的房东属于是低收入阶层（有工作但收入微薄）；\n",
    "- `'PTRATIO'` 是该地区的中学和小学里，学生和老师的数目比（`学生/老师`）。\n",
    "\n",
    "_凭直觉，上述三个特征中对每一个来说，你认为增大该特征的数值，`'MEDV'`的值会是**增大**还是**减小**呢？每一个答案都需要你给出理由。_\n",
    "\n",
    "**提示：**你预期一个`'RM'` 值是6的房屋跟`'RM'` 值是7的房屋相比，价值更高还是更低呢？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 问题 1 - 回答："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 编程练习 2: 数据分割与重排\n",
    "接下来，你需要把波士顿房屋数据集分成训练和测试两个子集。通常在这个过程中，数据也会被重排列，以消除数据集中由于顺序而产生的偏差。\n",
    "在下面的代码中，你需要\n",
    "\n",
    "将`features`和`prices`的数据都分成用于训练的数据子集和用于测试的数据子集。\n",
    "  - 分割比例为：80%的数据用于训练，20%用于测试；\n",
    "  - 选定一个数值以设定 `random_seed` ，这会确保结果的一致性；\n",
    "  - 提示：打乱训练集和测试集的数据时，只要创建一个 list，然后用这个 list 分别应用于 X，y 生成训练集和测试集。\n",
    " ```\n",
    " test = np.array([1, 3, 5, 7, 9, 11])\n",
    " \"\"\" test[[0,1,2]] = [1, 3, 5]\n",
    " \"\"\" test[[1,3,5]] = [3, 7, 11]\n",
    " ```\n",
    "  \n",
    "  可能需要用到的函数\n",
    "  - (numpy.random.seed)[https://docs.scipy.org/doc/numpy/reference/generated/numpy.random.seed.html]\n",
    "  - (numpy.random.shuffle)[https://docs.scipy.org/doc/numpy/reference/generated/numpy.random.shuffle.html]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "LEN, seed = 489, None\n",
    "def generate_train_and_test(X, y):\n",
    "    \"\"\"打乱并分割数据为训练集和测试集\"\"\"\n",
    "    \n",
    "\n",
    "X_train, X_test, y_train, y_test = generate_train_and_test(features.values, prices.values)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 问题 2 - 训练及测试\n",
    "*将数据集按一定比例分为训练用的数据集和测试用的数据集对学习算法有什么好处？*\n",
    "\n",
    "*如果果用模型已经见过的数据，例如部分训练集数据进行测试，又有什么坏处？*\n",
    "\n",
    "**提示：** 如果没有数据来对模型进行测试，会出现什么问题？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 问题 2 - 回答:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 第三步. 模型衡量标准"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 编程练习3：定义衡量标准\n",
    "如果不能对模型的训练和测试的表现进行量化地评估，我们就很难衡量模型的好坏。通常我们会定义一些衡量标准，这些标准可以通过对某些误差或者拟合程度的计算来得到。在这个项目中，你将通过运算[*决定系数*](http://stattrek.com/statistics/dictionary.aspx?definition=coefficient_of_determination) R<sup>2</sup> 来量化模型的表现。模型的决定系数是回归分析中十分常用的统计信息，经常被当作衡量模型预测能力好坏的标准。\n",
    "\n",
    "R<sup>2</sup>的数值范围从0至1，表示**目标变量**的预测值和实际值之间的相关程度平方的百分比。一个模型的R<sup>2</sup> 值为0还不如直接用**平均值**来预测效果好；而一个R<sup>2</sup> 值为1的模型则可以对目标变量进行完美的预测。从0至1之间的数值，则表示该模型中目标变量中有百分之多少能够用**特征**来解释。_模型也可能出现负值的R<sup>2</sup>，这种情况下模型所做预测有时会比直接计算目标变量的平均值差很多。_\n",
    "\n",
    "在下方代码的 `performance_metric` 函数中，你要实现：\n",
    "- 计算 `y_true` 和 `y_predict`的R<sup>2</sup>值，作为对其表现的评判，可参考[`r2_score`](http://scikit-learn.org/stable/modules/generated/sklearn.metrics.r2_score.html)。\n",
    "- 将他们的表现评分储存到`score`变量中。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# TODO 3\n",
    "\n",
    "# 提示： 导入r2_score\n",
    "\n",
    "def performance_metric(y_true, y_predict):\n",
    "    \"\"\"计算并返回预测值相比于预测值的分数\"\"\"\n",
    "    \n",
    "    score = None\n",
    "\n",
    "    return score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 问题 3 - 拟合程度\n",
    "\n",
    "假设一个数据集有五个数据且一个模型做出下列目标变量的预测：\n",
    "\n",
    "| 真实数值 | 预测数值 |\n",
    "| :-------------: | :--------: |\n",
    "| 3.0 | 2.5 |\n",
    "| -0.5 | 0.0 |\n",
    "| 2.0 | 2.1 |\n",
    "| 7.0 | 7.8 |\n",
    "| 4.2 | 5.3 |\n",
    "*你觉得这个模型已成功地描述了目标变量的变化吗？如果成功，请解释为什么，如果没有，也请给出原因。*  \n",
    "\n",
    "**提示**：运行下方的代码，使用`performance_metric`函数来计算模型的决定系数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 计算这个模型的预测结果的决定系数\n",
    "score = performance_metric([3, -0.5, 2, 7, 4.2], [2.5, 0.0, 2.1, 7.8, 5.3])\n",
    "print \"Model has a coefficient of determination, R^2, of {:.3f}.\".format(score)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 问题 3 - 回答:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第四步. 模型训练\n",
    "### 编程练习 4：训练回归模型\n",
    "在这个练习中，你将需要将所学到的内容整合，使用 **gradient descent 算法**训练一个线性回归模型。你可以尝试使用自己构建的多项式特征和 L1、L2 Loss，进行实验后，讨论他们是否对你的模型有效，并通过前面定义的 `performance_metric` 量化他们的提升效果。\n",
    "\n",
    "在这里，你不能使用现成 package，不能使用额外 data。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# TODO 4\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 问题 4 - 回归模型的优化\n",
    "在最基础的回归模型上，你使用了什么办法来提升模型的效果，最后模型的性能是否得到了提升？如果提升了，请说出提升性能的原理，如果没有，请探究没有生效的原因。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 问题 4 - 回答："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第六步. 做出预测\n",
    "当我们用数据训练出一个模型，它现在就可用于对新的数据进行预测。在决策树回归函数中，模型已经学会对新输入的数据*提问*，并返回对**目标变量**的预测值。你可以用这个预测来获取数据未知目标变量的信息，这些数据必须是不包含在训练数据之内的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 问题 5 - 预测销售价格\n",
    "想像你是一个在波士顿地区的房屋经纪人，并期待使用此模型以帮助你的客户评估他们想出售的房屋。你已经从你的三个客户收集到以下的资讯:\n",
    "\n",
    "| 特征 | 客戶 1 | 客戶 2 | 客戶 3 |\n",
    "| :---: | :---: | :---: | :---: |\n",
    "| 房屋内房间总数 | 5 间房间 | 4 间房间 | 8 间房间 |\n",
    "| 社区贫困指数（％被认为是贫困阶层） | 17% | 32% | 3% |\n",
    "| 邻近学校的学生-老师比例 | 15：1 | 22：1 | 12：1 |\n",
    "\n",
    "*你会建议每位客户的房屋销售的价格为多少？从房屋特征的数值判断，这样的价格合理吗？为什么？* \n",
    "\n",
    "**提示：**用你在**分析数据**部分计算出来的统计信息来帮助你证明你的答案。\n",
    "\n",
    "运行下列的代码区域，使用你的模型来为每位客户的房屋价值做出预测。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 生成三个客户的数据\n",
    "client_data = [[5, 17, 15], # 客户 1\n",
    "               [4, 32, 22], # 客户 2\n",
    "               [8, 3, 12]]  # 客户 3\n",
    "\n",
    "# 进行预测\n",
    "predicted_price = \n",
    "for i, price in enumerate(predicted_price):\n",
    "    print \"Predicted selling price for Client {}'s home: ${:,.2f}\".format(i+1, price)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 问题 5 - 回答："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 编程练习 5\n",
    "你刚刚预测了三个客户的房子的售价。在这个练习中，你将用你的最优模型在整个测试数据上进行预测, 并计算相对于目标变量的决定系数 R<sup>2</sup>的值**。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#TODO 5\n",
    "\n",
    "# 提示：你可能需要用到 X_test, y_test, performance_metric\n",
    "# 提示：你需要使用编程练习 4 中得到参数数值进行预测\n",
    "# 提示：你可能需要参考问题3的代码来计算R^2的值\n",
    "\n",
    "r2 = 1\n",
    "\n",
    "print \"Optimal model has R^2 score {:,.2f} on test data\".format(r2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 问题6 - 分析决定系数\n",
    "\n",
    "你刚刚计算了最优模型在测试集上的决定系数，你会如何评价这个结果？（你也可以尝试使用你的模型对问题 5 中三个客户的房屋价值进行预测，并与你之前的预测值进行对比）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 问题6 - 回答"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
